/**
 * Class: ParticleSource
 *
 * Purpose: 
 *
 * Created: Jan 23, 2010 @ 11:56:37 PM
 * @author Ken Scott
 */
package org.openfantasia.ps.particle;

import org.openfantasia.ps.particle.Particle;
import org.openfantasia.ps.particle.ParticleFactory;
import org.openfantasia.util.math.DPoint3;
import org.openfantasia.util.math.PMath;

import java.util.ArrayList;
import java.util.List;

public class ParticleSource extends Particle {

	public static final Particle DEFAULT = new ParticleSource();

	protected DPoint3 direction = new DPoint3(0, 1, 0);

	protected double rate = 1.0d;		// Particles per second

	protected double tAccum = 0.0d;

	protected List<ParticleFactory> factories = new ArrayList<ParticleFactory>();


	public ParticleSource() {
	}


	public ParticleSource(DPoint3 location, DPoint3 direction, double rate) {
		super(location);
		this.direction = direction;
		this.rate = rate;
	}


	public ParticleSource(DPoint3 location, DPoint3 velocity, DPoint3 direction, double rate) {
		super(location, velocity);
		this.direction = direction;
		this.rate = rate;
	}


	public ParticleSource(DPoint3 location, DPoint3 velocity, DPoint3 acceleration, DPoint3 direction, double rate) {
		super(location, velocity, acceleration);
		this.direction = direction;
		this.rate = rate;
	}


	public ParticleSource(ParticleSource that) {
		copy(that);
	}


	public void copy(ParticleSource that) {
		super.copy(that);

		this.direction = new DPoint3(that.direction);
		this.rate = that.rate;
		this.tAccum = that.tAccum;
		this.factories = new ArrayList<ParticleFactory>(that.factories);
	}


	public ParticleSource copy() {
		return new ParticleSource(this);
	}


	public void clear() {
		copy(DEFAULT);
	}


	public void tick(double time, double dt) {
		tAccum += dt;
		int count = (int) PMath.random(rate * tAccum);
		if (count > 0) {
			tAccum = 0;
		}
		for (int i = 0; i < count; i++) {
			Particle particle = newParticle();
			if (particle != null) {
				getSpace().addParticle(particle);
			}
		}

		super.tick(time, dt);
	}


	public DPoint3 getDirection() {
		return direction;
	}


	public void setDirection(DPoint3 direction) {
		this.direction = direction;
	}


	public double getRate() {
		return rate;
	}


	public void setRate(double rate) {
		this.rate = rate;
	}


	public void addParticleFactory(ParticleFactory factory) {
		if (!factories.contains(factory)) {
			factories.add(factory);
		}
	}


	public void removeParticleFactory(ParticleFactory factory) {
		factories.remove(factory);
	}


	public Particle newParticle() {
		Particle result = null;

		if (!factories.isEmpty()) {
			ParticleFactory factory = (ParticleFactory) PMath.random(factories);
			result = factory.newParticle();
			result = prepParticle(result);
		}

		return result;
	}


	public Particle prepParticle(Particle particle) {
		particle.setPosition(position);
		particle.setVelocity(velocity.copy().add(direction.copy().addNoise(1)));
		return particle;
	}
}
